package com.geovis.emergency.spd.controller.command;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.geovis.common.auth.util.AuthUtil;
import com.geovis.common.core.api.Result;
import com.geovis.emergency.spd.biz.iflytek.thread.PushThread;
import com.geovis.emergency.spd.biz.pc.service.*;
import com.geovis.emergency.spd.biz.pc.wrapper.PcDrillDisasterEventWrapper;
import com.geovis.emergency.spd.entity.command.pojo.vo.CommandDrillOrgVo;
import com.geovis.emergency.spd.entity.command.pojo.vo.CommandDrillPlanVO;
import com.geovis.emergency.spd.entity.command.pojo.vo.CommandDrillStepVO;
import com.geovis.emergency.spd.entity.pc.entity.*;
import com.geovis.emergency.spd.entity.pc.pojo.constant.PcDiscussConstant;
import com.geovis.emergency.spd.entity.pc.pojo.constant.PcDrillConstant;
import com.geovis.emergency.spd.entity.pc.pojo.constant.PcMessageConstant;
import com.geovis.emergency.spd.entity.pc.pojo.enums.TaskStatusEnum;
import com.geovis.emergency.spd.entity.pc.pojo.vo.PcDrillDisasterEventListVO;
import com.geovis.emergency.spd.entity.pc.pojo.vo.PcDrillPlanDetailVO;
import com.geovis.emergency.spd.entity.pc.pojo.vo.StringVO;
import com.geovis.emergency.spd.entity.pc.pojo.vo.TreeVO;
import com.geovis.emergency.spd.util.MsgUtil;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSort;
import com.google.common.collect.Lists;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 指挥调度大屏-演练相关接口
 * </p>
 *
 * @author Lonsho
 * @version 1.0
 * @date 2022/10/26
 */
@RestController
@RequestMapping("/command/drill")
@RequiredArgsConstructor
@Api(value = "指挥调度大屏-演练相关接口", tags = "指挥调度大屏-演练相关接口")
@Slf4j
@Validated
@ApiSort(1)
public class CommandDrillController {
    private final IPcDrillDisasterEventService drillDisasterEventService;
    private final IPcSchedulingEventService pcSchedulingEventService;
    private final IPcDrillDutyOrgService pcDrillDutyOrgService;

    private final IPcDrillDisasterEventService pcDrillDisasterEventService;
    private final IPcDrillPlanDetailService pcDrillPlanDetailService;

    private final IPcDrillPlanTaskService pcDrillPlanTaskService;
    private final IPcDutyService pcDutyService;

    private final IPcDrillService pcDrillService;

    private final IPcDiscussService pcDiscussService;

    private final IPcDrillPlanService pcDrillPlanService;

    private final IPcDrillDisasterService pcDrillDisasterService;

    @ApiImplicitParams({
            @ApiImplicitParam(paramType="header",name="appId",dataType="String",required=true,value="授权id"),
            @ApiImplicitParam(paramType="header",name="timestamp",dataType="String",required=true,value="当前时间戳(秒)"),
            @ApiImplicitParam(paramType="header",name="sign",dataType="String",required=true,value="签名"),
            @ApiImplicitParam(paramType="path",name="mainEventId",dataType="String",required=true,value="演练主事件id")

    })
    @ApiOperationSupport(order = 1)
    @ApiOperation(value = "演练事件列表", notes = "演练事件列表，签名生成方法：md5(appId+appSecret+timestamp)")
    @GetMapping("/eventList/{mainEventId}")
    public Result<List<PcDrillDisasterEventListVO>> eventList(@PathVariable("mainEventId") String mainEventId) {
        PcSchedulingEvent pcSchedulingEvent = pcSchedulingEventService.getMainEventId(mainEventId);
        Assert.notNull(pcSchedulingEvent,"事件不存在，请先推送事件");
        isExistDrill(pcSchedulingEvent.getDrillId());
        List<PcDrillDisasterEventListVO> list = drillDisasterEventService.getList(pcSchedulingEvent.getDrillId(), null);
        Collections.reverse(list);
        return Result.ok(list);
    }
    @ApiImplicitParams({
            @ApiImplicitParam(paramType="header",name="appId",dataType="String",required=true,value="授权id"),
            @ApiImplicitParam(paramType="header",name="timestamp",dataType="String",required=true,value="当前时间戳(秒)"),
            @ApiImplicitParam(paramType="header",name="sign",dataType="String",required=true,value="签名"),
            @ApiImplicitParam(paramType="path",name="drillEventId",dataType="String",required=true,value="演练事件id")
    })
    @ApiOperationSupport(order = 2)
    @ApiOperation(value = "工作方案列表", notes = "工作方案列表，签名生成方法：md5(appId+appSecret+timestamp)")
    @GetMapping("/planList/{drillEventId}")
    public Result<List<CommandDrillPlanVO>> planList(@PathVariable("drillEventId") String drillEventId) {
        PcDrillDisasterEvent pcDrillDisasterEvent = pcDrillDisasterEventService.getById(drillEventId);
        List<CommandDrillPlanVO> list = Lists.newArrayList();
        if (ObjectUtil.isNotNull(pcDrillDisasterEvent)){
            List<StringVO> groupList = pcDrillDutyOrgService.dutyGroupList(pcDrillDisasterEvent.getPcDrillId());
            List<PcDrillPlanDetail> pcDrillPlanDetailList = pcDrillPlanDetailService.list(
                    Wrappers.lambdaQuery(PcDrillPlanDetail.class)
                            .eq(PcDrillPlanDetail::getPcDrillId,pcDrillDisasterEvent.getPcDrillId())
                            .eq(PcDrillPlanDetail::getPcDrillDisasterEventId,drillEventId)
            );
            List<PcDrillPlanDetailVO> drillPlanDetailVOList = PcDrillDisasterEventWrapper
                    .build(null, pcDrillPlanDetailService, pcDrillPlanTaskService, null)
                    .getDrillPlanDetailVOList(pcDrillPlanDetailList);
            for (StringVO stringVO : groupList) {
                CommandDrillPlanVO commandDrillPlanVO = new CommandDrillPlanVO();
                commandDrillPlanVO.setId(stringVO.getId());
                commandDrillPlanVO.setGroupName(stringVO.getName());
                List<PcDrillPlanDetailVO> collect = drillPlanDetailVOList.stream().filter(s -> s.getGroupId().equals(stringVO.getId())).collect(Collectors.toList());
                commandDrillPlanVO.setDrillPlanDetailList(collect);
                commandDrillPlanVO.setTotalCount(collect.size());
                //方案审核通过以及方案均审核通过，即为已完成
                long count = collect.stream().filter(s -> TaskStatusEnum.PASS.getCode().equals(s.getStatus()) && TaskStatusEnum.PASS.getCode().equals(s.getFeedbackStatus())).count();
                commandDrillPlanVO.setCompleteCount(Integer.valueOf(String.valueOf(count)));
                list.add(commandDrillPlanVO);
            }
        }
        return Result.ok(list);
    }
    @ApiImplicitParams({
            @ApiImplicitParam(paramType="header",name="appId",dataType="String",required=true,value="授权id"),
            @ApiImplicitParam(paramType="header",name="timestamp",dataType="String",required=true,value="当前时间戳(秒)"),
            @ApiImplicitParam(paramType="header",name="sign",dataType="String",required=true,value="签名"),
            @ApiImplicitParam(paramType="path",name="mainEventId",dataType="String",required=true,value="演练主事件id")
    })
    @ApiOperationSupport(order = 3)
    @ApiOperation(value = "值班编组（组织架构）", notes = "值班编组（组织架构），签名生成方法：md5(appId+appSecret+timestamp)")
    @GetMapping("/dutyGroup/{mainEventId}")
    public Result<List<TreeVO>> dutyGroup(@PathVariable("mainEventId") String mainEventId){
        PcSchedulingEvent pcSchedulingEvent = pcSchedulingEventService.getMainEventId(mainEventId);
        Assert.notNull(pcSchedulingEvent,"事件不存在，请先推送事件");
        isExistDrill(pcSchedulingEvent.getDrillId());
        List<TreeVO> treeVOList = pcDutyService.dutyTree(pcSchedulingEvent.getDrillId(), null, true);
        return Result.ok(treeVOList);
    }
    @ApiImplicitParams({
            @ApiImplicitParam(paramType="header",name="appId",dataType="String",required=true,value="授权id"),
            @ApiImplicitParam(paramType="header",name="timestamp",dataType="String",required=true,value="当前时间戳(秒)"),
            @ApiImplicitParam(paramType="header",name="sign",dataType="String",required=true,value="签名"),
            @ApiImplicitParam(paramType="path",name="mainEventId",dataType="String",required=true,value="演练主事件id")
    })
    @ApiOperationSupport(order = 4)
    @ApiOperation(value = "演练步骤", notes = "演练步骤，签名生成方法：md5(appId+appSecret+timestamp)")
    @GetMapping("/step/{mainEventId}")
    public Result<List<CommandDrillStepVO>> drillStep(@PathVariable("mainEventId") String mainEventId){
        PcSchedulingEvent pcSchedulingEvent = pcSchedulingEventService.getMainEventId(mainEventId);
        PcDrill pcDrill = null;
        if (ObjectUtil.isNotNull(pcSchedulingEvent) && ObjectUtil.isNotNull(pcSchedulingEvent.getDrillId())) {
            pcDrill = pcDrillService.getById(pcSchedulingEvent.getDrillId());
        }
        List<String> defaultTitleList = Lists.newArrayList("事件接报", "启动指挥", "研判会商", "任务执行", "总结评估");
        List<CommandDrillStepVO> stepList = Lists.newArrayList();
        int index = 0;
        int currentIndex = 0;
        for (String title : defaultTitleList) {
            CommandDrillStepVO commandDrillStepVO = new CommandDrillStepVO();
            commandDrillStepVO.setName(title);
            commandDrillStepVO.setIsCurrent(false);
            switch (index) {
                case 0:
                    //事件接报
                    if (ObjectUtil.isNotNull(pcSchedulingEvent)){
                        currentIndex = index;
                    }
                    break;
                case 1:
                    //启动指挥
                    if (ObjectUtil.isNotNull(pcDrill) && !PcDrillConstant.STATUS_PREPARE.equals(pcDrill.getStatus())){
                        currentIndex = index;
                    }
                    break;
                case 2:
                    //研判会商
                    if (ObjectUtil.isNotNull(pcDrill) && PcDrillConstant.STATUS_DOING.equals(pcDrill.getStatus())){
                        //研判会商次数
                        long count = pcDiscussService.count(
                                Wrappers.lambdaQuery(PcDiscuss.class)
                                        .eq(PcDiscuss::getPcDrillId, pcDrill.getId())
                        );
                        commandDrillStepVO.setCount(count);
                        //获取最后一次研判会商
                        PcDiscuss pcDiscuss = pcDiscussService.getOne(
                                Wrappers.lambdaQuery(PcDiscuss.class)
                                        .eq(PcDiscuss::getPcDrillId, pcDrill.getId())
                                        .orderByDesc(PcDiscuss::getCreateTime)
                                        .last("limit 1")
                        );
                        if (ObjectUtil.isNotNull(pcDiscuss) && PcDiscussConstant.STATUS_DOING.equals(pcDiscuss.getStatus())){
                            currentIndex = index;
                        }
                    }
                    break;
                case 3:
                    //任务执行
                    if (ObjectUtil.isNotNull(pcDrill) && PcDrillConstant.STATUS_DOING.equals(pcDrill.getStatus())){
                        //任务执行次数
                        long count = pcDrillPlanService.count(
                                Wrappers.lambdaQuery(PcDrillPlan.class)
                                        .eq(PcDrillPlan::getPcDrillId, pcDrill.getId())
                        );
                        commandDrillStepVO.setCount(count);
                        if (currentIndex != 2){
                            if (count > 0){
                                currentIndex = index;
                            }
                        }
                    }
                    break;
                case 4:
                    //工作总结
                    if (ObjectUtil.isNotNull(pcDrill) && PcDrillConstant.STATUS_COMPLETE.equals(pcDrill.getStatus())){
                        currentIndex = index;
                    }
                    break;
                default:
                    break;
            }
            stepList.add(commandDrillStepVO);
            index++;
        }
        stepList.get(currentIndex).setIsCurrent(true);
        return Result.ok(stepList);
    }
    @ApiImplicitParams({
            @ApiImplicitParam(paramType="header",name="appId",dataType="String",required=true,value="授权id"),
            @ApiImplicitParam(paramType="header",name="timestamp",dataType="String",required=true,value="当前时间戳(秒)"),
            @ApiImplicitParam(paramType="header",name="sign",dataType="String",required=true,value="签名"),
            @ApiImplicitParam(paramType="path",name="mainEventId",dataType="String",required=true,value="演练主事件id")
    })
    @ApiOperationSupport(order = 4)
    @ApiOperation(value = "结束演练", notes = "结束演练，签名生成方法：md5(appId+appSecret+timestamp)")
    @PostMapping("/endPcDrill/{mainEventId}")
    public Result endPcDrill(@PathVariable("mainEventId") String mainEventId) {
        pcDrillService.endPcDrill(mainEventId);
        return Result.ok();
    }
    private void isExistDrill(String drillId){
        Assert.isFalse(StrUtil.isBlank(drillId),"演练尚未创建");
        PcDrill pcDrill = pcDrillService.getById(drillId);
        Assert.notNull(pcDrill,"演练不存在");
        Assert.isFalse(PcDrillConstant.STATUS_PREPARE.equals(pcDrill.getStatus()),"演练尚未启动");
    }



}
